---
title: 建造者模式
description: Builder Pattern - 将一个复杂对象的构建与它的表示分离，使得同样的构建过程可以创建不同的表示
sidebar_position: 4
---

# 建造者模式

## 模式概述

### 定义
建造者模式（Builder Pattern）是一种创建型设计模式，它**将一个复杂对象的构建过程与它的表示分离，使得同样的构建过程可以创建不同的表示**。
![](https://wkq-img.oss-cn-chengdu.aliyuncs.com/site/20250728235754.png)
### 建造者模式要解决的问题
建造者模式可以将部件和其组装过程分开，一步一步**创建一个复杂的对象（包含多个成员变量的对象）**。用户只需要制定复杂对象的类型就可以得到该对象，而无需知道其内部的具体的构造细节。

:::tip
想象你去一家餐厅点餐，服务员会问你："需要什么口味？需要加辣吗？需要配饮料吗？"等一系列问题。这个过程就像建造者模式，通过一步步设置不同的选项，最终完成一份完整的订单。
:::

### 为什么需要建造者模式？
假设我们需要创建一个资源池配置类：

```java
public class ResourcePoolConfig {
    private String name;
    private int maxTotal;
    private int maxIdle;
    private int minIdle;

    public ResourcePoolConfig(String name, Integer maxTotal, Integer maxIdle, Integer minIdle) {
        if (StringUtils.isBlank(name)) {
            throw new IllegalArgumentException("name should not be empty.");
        }
        this.name = name;

        if (maxTotal != null) {
            if (maxTotal <= 0) {
                throw new IllegalArgumentException("maxTotal should be positive.");
            }
            this.maxTotal = maxTotal;
        }

        if (maxIdle != null) {
            if (maxIdle < 0) {
                throw new IllegalArgumentException("maxIdle should not be negative.");
            }
            this.maxIdle = maxIdle;
        }

        if (minIdle != null) {
            if (minIdle < 0) {
                throw new IllegalArgumentException("minIdle should not be negative.");
            }
            this.minIdle = minIdle;
        }
    }
}
```

这种实现方式有以下问题：
1. 构造函数参数过多，容易出错。
2. 参数之间可能有依赖关系，需要校验，破坏了不可变对象的封闭性。
3. 代码可读性差，难以维护。

## 建造者模式实现

### 基本实现
```java
public class ResourcePoolConfig {
    private String name;
    private int maxTotal;
    private int maxIdle;
    private int minIdle;

    private ResourcePoolConfig(Builder builder) {
        this.name = builder.name;
        this.maxTotal = builder.maxTotal;
        this.maxIdle = builder.maxIdle;
        this.minIdle = builder.minIdle;
    }

    //建造者类
    public static class Builder {
        private static final int DEFAULT_MAX_TOTAL = 8;
        private static final int DEFAULT_MAX_IDLE = 8;
        private static final int DEFAULT_MIN_IDLE = 0;

        private String name;
        private int maxTotal = DEFAULT_MAX_TOTAL;
        private int maxIdle = DEFAULT_MAX_IDLE;
        private int minIdle = DEFAULT_MIN_IDLE;

        public Builder setName(String name) {
            if (StringUtils.isBlank(name)) {
                throw new IllegalArgumentException("name should not be empty.");
            }
            this.name = name;
            return this;
        }

        public Builder setMaxTotal(int maxTotal) {
            if (maxTotal <= 0) {
                throw new IllegalArgumentException("maxTotal should be positive.");
            }
            this.maxTotal = maxTotal;
            return this;
        }

        public Builder setMaxIdle(int maxIdle) {
            if (maxIdle < 0) {
                throw new IllegalArgumentException("maxIdle should not be negative.");
            }
            this.maxIdle = maxIdle;
            return this;
        }

        public Builder setMinIdle(int minIdle) {
            if (minIdle < 0) {
                throw new IllegalArgumentException("minIdle should not be negative.");
            }
            this.minIdle = minIdle;
            return this;
        }

        public ResourcePoolConfig build() {
            // 校验逻辑放到这里来做，包括必填项校验、依赖关系校验、约束条件校验等
            if (StringUtils.isBlank(name)) {
                throw new IllegalArgumentException("name should not be empty.");
            }
            if (maxIdle > maxTotal) {
                throw new IllegalArgumentException("maxIdle cannot be greater than maxTotal.");
            }
            if (minIdle > maxTotal || minIdle > maxIdle) {
                throw new IllegalArgumentException("minIdle cannot be greater than maxTotal or maxIdle.");
            }

            return new ResourcePoolConfig(this);
        }
    }
}
```

### 使用示例
```java
// 使用建造者模式
ResourcePoolConfig config = new ResourcePoolConfig.Builder()
        .setName("dbconnectionpool")
        .setMaxTotal(16)
        .setMaxIdle(10)
        .setMinIdle(2)
        .build();
```

## 应用场景

### 1. 构造参数过多
当一个类的构造函数参数超过4个，使用构造函数就会导致代码可读性差，使用建造者模式更合适。

### 2. 参数之间有依赖关系
当参数之间有一定的约束条件时，使用构造函数很难做参数校验，建造者模式可以在build()方法中统一校验。

### 3. 需要创建不可变对象
建造者模式创建的对象是不可变的，所有的属性都在构建时设置好。

## 最佳实践

### 1. 链式调用
返回this可以实现链式调用，提高代码的可读性：
```java
Builder setXxx(xxx) {
    this.xxx = xxx;
    return this;
}
```

### 2. 参数校验
- 必填参数校验可以放在setter方法中
- 参数之间的依赖关系校验放在build()方法中
- 提供默认值，减少客户端代码的设置

### 3. 不可变性
- 将构造函数设置为private
- 不提供setter方法
- 所有属性设置为final

## 建造者模式变体

### 1. 静态内部类方式
```java
public class ResourcePoolConfig {
    private final String name;
    private final int maxTotal;
    private final int maxIdle;
    private final int minIdle;

    private ResourcePoolConfig(Builder builder) { /*...*/ }

    public static class Builder { /*...*/ }
}
```

### 2. 链式调用方式
```java
public class ResourcePoolConfig {
    public ResourcePoolConfig name(String name) {
        this.name = name;
        return this;
    }
    // 其他setter方法
}
```

## 与其他模式的区别

### 1. 工厂模式 vs 建造者模式
- 工厂模式：关注一个产品整体的创建方法
- 建造者模式：关注一个产品各个部分的创建过程

### 2. 抽象工厂 vs 建造者模式
- 抽象工厂：创建多个产品族中的产品
- 建造者模式：一步步创建一个复杂的产品

